package com.zyy.game.tianlong.network;

import com.zyy.game.tianlong.network.config.NettyConfig;
import com.zyy.game.tianlong.network.callback.GlobalExceptionCallBack;
import com.zyy.game.tianlong.network.codec.GameWebSocketDecoder;
import com.zyy.game.tianlong.network.codec.GameWebSocketEncoder;
import com.zyy.game.tianlong.network.exception.ThreadRejectedException;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import lombok.extern.slf4j.Slf4j;

/**
 * webSocket ChannelInitializer
 *
 * @author relufi
 * @date 2019/7/27 0027
 */
@ChannelHandler.Sharable
@Slf4j
public class GameWebSocketChannelInitializer extends ChannelInitializer<NioSocketChannel> {
    private final GlobalExceptionCallBack globalExceptionCallBack;
    private final NettyConfig nettyConfig;
    private final DefaultEventExecutorGroup businessGroup;
    private final GameDispatcher gameMsgHandler;

    private GameWebSocketEncoder gameWebSocketEncoder = new GameWebSocketEncoder();
    private GameWebSocketDecoder gameWebSocketDecoder;
    private ShowHexDump showHexDump = new ShowHexDump();

    public GameWebSocketChannelInitializer(GlobalExceptionCallBack globalExceptionCallBack, NettyConfig nettyConfig, DefaultEventExecutorGroup businessGroup, GameDispatcher gameMsgHandler) {
        this.globalExceptionCallBack = globalExceptionCallBack;
        this.nettyConfig = nettyConfig;
        this.businessGroup = businessGroup;
        this.gameMsgHandler = gameMsgHandler;
        gameWebSocketDecoder = new GameWebSocketDecoder(globalExceptionCallBack);
    }

    @Override
    protected void initChannel(NioSocketChannel ch) {
        if (nettyConfig.isShowHexDump()) {
            ch.pipeline().addLast("showHexDump", showHexDump);
        }
        ch.pipeline()
                .addLast(new HttpServerCodec())
                //ChunkedWriteHandler分块写处理，文件过大会将内存撑爆
                .addLast(new ChunkedWriteHandler())
                /*
                  作用是将一个Http的消息组装成一个完成的HttpRequest或者HttpResponse，那么具体的是什么
                  取决于是请求还是响应, 该Handler必须放在HttpServerCodec后的后面
                 */
                .addLast(new HttpObjectAggregator(65536))
                //用于处理websocket, /ws为访问websocket时的uri
                .addLast(new WebSocketServerProtocolHandler("/game"))
                .addLast(gameWebSocketEncoder)
                .addLast(gameWebSocketDecoder)
                .addLast(businessGroup, "gameHandler", gameMsgHandler);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof ThreadRejectedException) {
            globalExceptionCallBack.exceptionCaught(new GameContext(ctx), cause);
        } else {
            super.exceptionCaught(ctx, cause);
        }
    }
}
